package gfx.hdr;

import gfx.layers.Layer;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;

public class Exposure extends Layer{
	private int[] luminances;
	private ImageHDR hdrContext;
	private int relevantPixelCount = -1;
	
	private int lowerRelevanceBorder = 20;
	private int upperRelevanceBorder = 245;
	
	private double relativeExposure = 0;
		
	
	public Exposure(Layer layer, ImageHDR hdrContext){
		super(layer.getImage(), layer.getName(), layer.getLayerManager());
		
		this.hdrContext = hdrContext;		
		initializeLuminances();
	}
	
	private void initializeLuminances(){
		ColorConvertOp grayScaleOp = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
		BufferedImage imageLum = grayScaleOp.filter(image, null);
		int[] lum = imageLum.getData().getPixels(0, 0, hdrContext.getWidth(), hdrContext.getHeight(), (int[])null);
		luminances = new int[lum.length / 4];
		for(int i = 0; i < lum.length; i++){
			luminances[i / 4] <<= 8;
			luminances[i / 4] |= lum[i];
		}
	}
	
	public int getLuminance(int pixelIndex){
		int idx = pixelIndex / 4;
		int byt = 3 - pixelIndex % 4;
		return (luminances[idx] >> (byt * Byte.SIZE)) & 0x000000ff;
	}
	
	public void bitFlagExposureRelevantAreas(int[] pixelsBitFlagged, int bitPosition){
		int bitMask = 1 << bitPosition;
		relevantPixelCount = 0;
		
		for(int i = 0; i < pixelsBitFlagged.length; i++){
			int lum = getLuminance(i);
			if(lum >= lowerRelevanceBorder && lum <= upperRelevanceBorder){
				pixelsBitFlagged[i] |= bitMask;
				relevantPixelCount++;
			}
		}
	}
	
	public int getRelevantPixelCount(){
		return relevantPixelCount;
	}
	
	public void setRelevanceBorders(int lowerRelevanceBorder, int upperRelevanceBorder){
		this.lowerRelevanceBorder = lowerRelevanceBorder;
		this.upperRelevanceBorder = upperRelevanceBorder;
	}
	
	public void setRelativeExposure(double relativeExposure){
		this.relativeExposure = relativeExposure;
	}
	
	public double getRelativeExposure(){
		return relativeExposure;
	}
	
	public static double sliderToExposure(int slid){
		return Math.pow(2, (double)(slid - 64) / 16);
	}
	
	public static int exposureToSlider(double expo){
		return (int)(Math.log(expo) / Math.log(2)) * 16 + 64;
	}
}
